#include "uthreads.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>

#define FAIL -1

#define SUCCESS 0

int gotIt = 0;
int gotIt2 = 0;

void a();
void b();
void c();
void d();
void e();
void f();
void g();
void h();
void i();
void j();
void k();
void l();
void m();
void n();
void o();
void p();


int ba = 0;
int bb = 0;




//Blocks the SIGVTALARM signal

void hanldeAwakeningThread1(int sig) {
	//assignThreadToReadyQueue(sleeping_thread_id);
	//struct timeval tempTime;
	//gettimeofday(&tempTime, NULL);
	//printf("Thread id: %d is awake and the time is: %ld\n", sleeping_thread_id,
	//			tempTime.tv_sec);
	//sleeping_thread_id = -1;
	gotIt2 = 5;
	//makeSchedualeDecision();
}

int blockAwakeningThreadSig1() {
	sigset_t set;
	sigemptyset(&set);
	sigaddset(&set, SIGVTALRM);
	sigprocmask(SIG_SETMASK, &set, NULL);
	gotIt2 = 0;
	return SUCCESS;
}

int unblockAwakeningThreadSig1() {
	sigset_t set;
	sigemptyset(&set);
	gotIt2 = 0;
	sigprocmask(SIG_SETMASK, &set, NULL);
	return SUCCESS;
}


void test_func_1 (){
	//	int i=0;
	//	for(i=0;i<10;i++){
	//		printf("inside loop 1 and count is: %d\n",i);
	//	}
	gotIt2 = -1;
	thread_terminate(thread_gettid());
}

void test_func_2 (){
	//	int i=0;
	//	for(i=0;i<10;i++){
	//		printf("inside loop 2 and count is: %d\n",i);
	//	}
	thread_terminate(thread_gettid());
}

void test_func_3 (){
	//	int i=0;
	//	for(i=0;i<10;i++){
	//		printf("inside loop 3 and count is: %d\n",i);
	//	}
	thread_spawn(test_func_2,2);
	//printf("func3 continues\n");
	thread_terminate(thread_gettid());
}


void test_func_4()
{
	//printf("Running thread id: %d\n", thread_gettid());
	gotIt2++;
	thread_sleep(thread_gettid(), 2500);
	gotIt2++;
	//printf("About to terminate myself, id:%d\n", thread_gettid());
	gotIt = 1;
	thread_terminate(thread_gettid());
}

void test_func_5 (){
	gotIt = 1;
	thread_terminate(thread_gettid());
}

void test_func_6 (){
	thread_suspend(thread_gettid());
	gotIt = 1;
	thread_terminate(thread_gettid());
}

int test_spawn_function();
void testMakeSchedulaingDecision();
void testQueueAssignments();
void testSleepAndAwakeThreads();
void testTimeStamps();

void runTestScenario(int scenarioNum);


void checkBlockPostpone(){
	struct sigaction new_action;
	new_action.sa_handler = hanldeAwakeningThread1;
	sigemptyset(&new_action.sa_mask);
	new_action.sa_flags = 0;
	sigaction(SIGVTALRM, &new_action, NULL);
	struct itimerval tv;
	tv.it_value.tv_sec = 1; //time of first timer
	tv.it_value.tv_usec = 0; //time of first timer
	tv.it_interval.tv_sec = 0; //time of all timers but the first one
	tv.it_interval.tv_usec = 0; //time of all timers but the first one
	setitimer(ITIMER_VIRTUAL, &tv, NULL);
	struct timeval now;
	gettimeofday(&now,NULL);
	struct timeval cmp;
	gettimeofday(&cmp,NULL);
	//blockAwakeningThreadSig1();
	while(now.tv_sec+5>cmp.tv_sec){
		gettimeofday(&cmp,NULL);
	}
	//unblockAwakeningThreadSig1();
	if(gotIt2 != 5){
		printf("signal was not handled\n");
	}
	else{
		printf("success\n");
	}
}


int main(int argc, char **argv) {
	int i=0;
	printf("Testing:\n");
	if(thread_lib_init() == FAIL){
		printf("Error: Thread lib Init FAILED\n");
		exit(0);
	}
	//test_spawn_function();
	//testQueueAssignments();
	//testSleepAndAwakeThreads();
	//testMakeSchedulaingDecision();
	//thread_terminate(thread_gettid());




	//initiate
	printf( "1) initiate lib with main id:%d.\n",thread_gettid());
	//create thread with lower priority
	thread_spawn(f, 18);
	printf( "2) created f, main continues.\n" );
	//update to the same priority, should do nothing
	thread_set_priority(1, 16);
	printf( "3) f higher priority\n" );
	thread_set_priority(1, 20);
	thread_spawn(g, 18);
	printf( "4) created g, main continues.\n" );
	//update to the main's priority, should do nothing
	thread_set_priority(0, 18);
	printf( "5) updates main's priority, main continues\n ");
	thread_set_priority(0, 2);
	printf( "6) updates main's priority, main continues\n ");
	thread_set_priority(0, 30);
	printf( "9) f finished\n");
	thread_set_priority(0, 15);
	thread_spawn(a, 10);
	printf( "15) back from a\n" );
	thread_spawn(h, 17);
	thread_spawn(d, 14);
	printf( "21) back in main\n" );
	thread_set_priority(0, 15);
	thread_spawn(e, 20);
	thread_spawn(j, 18);
	thread_set_priority(9, 18);
	thread_set_priority(0, 19);
	printf( "24) back in main \n" );
	thread_spawn(k,32);
	thread_set_priority(11, 14);
	printf( "26) back in main \n" );
	//waste time
	for (i=0; i<10000000; i++){}
	printf( "27) still in main \n" );

	thread_spawn(l,32);
	thread_sleep(12,1);
	thread_set_priority(12,12);
	while (bb==0){
	}
	printf( "30)back from l and k \n" );
	thread_spawn(m,14);
	printf( "32) back in main \n" );
	thread_set_priority(13,19);
	thread_resume(13);
	printf( "33) still in main \n" );
	thread_spawn(n,32);
	thread_suspend(14);
	thread_set_priority(14,12);
	thread_resume(14);
	printf( "36)back from n and m \n" );
	thread_spawn(o,10);
	printf( "38)o suspended\n" );
	unblockAwakeningThreadSig1();
	thread_sleep(15,1);
	while (ba==0){
	}
	printf( "40)main's back\n" );
	return 0;
}



void d(){
	printf( "16) d started\n");
	thread_spawn(i, 17);
	thread_suspend(6);
	printf( "17) suspend h\n");
	//waist time
	int i;
	for (i=0; i<100000; i++){}
	thread_resume(6);
	printf( "18) wake h\n");
	thread_set_priority(0, 30);
	int temp = thread_gettid();
	thread_terminate(temp);
}


void o(){
	printf( "37)in o\n");
	thread_suspend(thread_gettid());
	ba = 1;
	printf( "39) o comes back after sleeping\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}


void m(){
	printf( "31)in m\n");
	thread_suspend(thread_gettid());
	printf( "35) m comes back\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void n(){
	printf( "34) l wakes up and start running\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}


void i(){
	printf( "19) i runs - waited the most in ready state\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}


void l(){
	printf( "28) l wakes up and start running\n" );
	bb = 1;
	int temp = thread_gettid();
	thread_terminate(temp);
}


void h(){
	printf( "20) h runs - waited less then i because suspended\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}


void e(){
	printf( "22) e runs\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void j(){
	printf( "23) j runs\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void k(){
	printf( "25)in k\n");
	thread_set_priority(thread_gettid(),19);
	thread_sleep(thread_gettid(),10);
	printf( "29) k comes back\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void f(){
	printf( "8) g finished, f started\n");
	int temp = thread_gettid();
	thread_terminate(temp);
}

void g(){
	printf( "7) g started\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void c(){
	printf( "12) c started\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void b(){
	printf( "13) in b - b waited the most\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}

void a(){
	printf( "10) a started\n" );
	thread_spawn(b, 10);
	printf( "11) b created\n" );
	thread_spawn(c, 1);
	printf( "14) back from b\n" );
	int temp = thread_gettid();
	thread_terminate(temp);
}
